import Component from 'vue-class-component';
import styles from './style.module.less';
import { Prop } from 'vue-property-decorator';
import BaseVue from '@/lib/base/BaseVue';
import apicloud from '@/config/apicloud';


@Component
export default class extends BaseVue {

    @Prop({
        default: "rgba(0,0,0,0)"
    })
    private bgColor!: string;

    // 下拉刷新图标
    @Prop({
        default() {
            return apicloud.REFRESH_HEADER.load
        }
    })
    private icons!: string[];
    // 下拉过程显示图标所引
    @Prop({
        default: apicloud.REFRESH_HEADER.defaultIndex
    })
    private defaultIndex!: number;

    /**
     * 下拉刷新动画间隔
     */
    @Prop({
        default: apicloud.REFRESH_HEADER.animationStep
    })
    protected animationStep!: number;

    // 第一次触摸坐标
    private startX = 0;
    private startY = 0;
    // 滑动距离
    private translateDistance = 0;
    // 多点触摸时，最后手指抬起时的滑动距离
    private lastEndTranslateDistance = 0;

    // 状态 pull 下拉中 ， loading 加载中 ，end 结束
    private status: 'pull' | 'loading' | 'end' = 'end';

    // 头部高度
    private headerHeight = 0;

    // 动画索引
    private animationIndex = 0;
    // 是否执行过结束方法
    private isRunDone = false;



    /**
     * 下拉样式
     */
    private get styles() {
        return {
            webkitTransform: `translateY(${this.translateDistance}px)`,
            transform: `translateY(${this.translateDistance}px)`,
        }
    }
    /**
     * 头部下拉缩放动画
     */
    private get pullIconStyles() {
        let scale = this.translateDistance / this.headerHeight;
        if (scale > 1) {
            scale = 1;
        }
        if (isNaN(scale)) {
            scale = 0;
        }
        return {
            webkitTransform: `scale(${scale})`,
            transform: `scale(${scale})`,
            webkitTransition: scale === 0 ? 'all .3s' : 'none',
            transition: scale === 0 ? 'all .3s' : 'none'
        }
    }



    public render() {
        const icons = this.icons.map((icon, i) => {
            return <div class={[styles.icon, this.animationIndex === i && styles.show]} style={{ backgroundImage: `url(${icon})` }}></div>
        });
        return (
            <div ref="app" class={styles.app} style={{ background: this.bgColor }}>
                <div ref="content" class={styles.content} style={this.styles}>
                    <div ref="header" staticClass={styles.header} style={this.pullIconStyles}>
                        <div class={styles.iconBox}>
                            {icons}
                        </div>
                    </div>
                    {this.$slots.default}
                </div>
            </div>
        )
    }

    public created() {
        this.$nextTick(() => {
            const app = this.$refs.app as HTMLDivElement;
            const header = this.$refs.header as HTMLDivElement;
            this.headerHeight = header.offsetHeight;
            app.addEventListener('touchstart', this, false);
        });
    }


    public handleEvent(evt: TouchEvent) {

        const touch = evt.touches[0];
        const element = this.$refs.content as HTMLDivElement;
        switch (evt.type) {
            case 'touchstart':
                // 多点触摸 
                if (evt.touches.length > 1) {
                    return;
                }

                const app = this.$refs.app as HTMLDivElement;
                app.addEventListener('touchmove', this, false);
                app.addEventListener('touchend', this, false);
                app.addEventListener('touchcancel', this, false);
                if (this.isRunDone) {
                    this.isRunDone = false;
                    this.status = 'end';
                }
                //  在loading状态
                if (this.status === 'loading') {
                    return;
                }

                element.style.transition = 'none';
                element.style.webkitTransition = 'none';
                // 不是在最顶部时 不记录坐标
                if (!this.isTopmost()) {
                    return;
                }
                this.startX = touch.clientX;
                this.startY = touch.clientY;
                break;
            case 'touchmove': {
                if (evt.touches.length > 1) {
                    // 多点触摸时 滑动距离不为0时，禁止滚动
                    if (this.translateDistance) {

                        evt.preventDefault();
                    }
                    return;
                }
                const moveX = touch.clientX;
                const moveY = touch.clientY;
                // loading 状态不滑动
                if (this.status === 'loading') {
                    evt.preventDefault();
                    return;
                }
                //（不在最顶部 || 不是往下拉）&& 滑动距离小于等于0了
                if ((!this.isTopmost() || !this.isPullDown(moveX, moveY)) && this.translateDistance <= 0) {
                    return;
                }
                // 当从 滚动  过继 到下拉刷新时
                if (this.startY === 0) {
                    this.startX = moveX;
                    this.startY = moveY;
                }
                this.status = 'pull';
                const distance = this.getDistance(moveY);
                this.translateDistance = distance;
                evt.preventDefault();
                break;
            }
            case 'touchend':
            case 'touchcancel': {
                if (evt.touches.length > 0) {
                    // 多点触摸时，有手指抬起，开始坐标 变成当前第一个触摸点的坐标
                    this.startY = evt.touches[0].clientY;
                    this.startX = evt.touches[0].clientX;
                    // 记录上次滑动距离
                    this.lastEndTranslateDistance = this.translateDistance;
                    evt.stopImmediatePropagation();
                    return;
                }

                const app = this.$refs.app as HTMLDivElement;
                app.removeEventListener('touchmove', this, false);
                app.removeEventListener('touchend', this, false);
                app.removeEventListener('touchcancel', this, false);
                if (this.isRunDone) {
                    this.isRunDone = false;
                    this.status = 'end';
                }

                if (this.status === 'pull') {
                    evt.stopImmediatePropagation();
                } else if (this.status === 'loading') {

                    return;
                }
                this.next();
                break;
            }

        }
    }

    /**
     * 下拉结束
     */
    public done() {
        this.startX = 0;
        this.startY = 0;
        this.isRunDone = true;
        this.translateDistance = 0;
        this.lastEndTranslateDistance = 0;
        this.animationIndex = this.defaultIndex;
        this.status = 'end';
    }


    /**
     *  抬起后是否出发下拉刷新事件
     */
    private next() {
        const element = this.$refs.content as HTMLDivElement;
        element.style.transition = 'transform .3s';
        element.style.webkitTransition = 'transform .3s';
        this.startX = 0;
        this.startY = 0;
        this.lastEndTranslateDistance = 0;
        if (this.translateDistance > this.headerHeight * 1.5) {
            this.translateDistance = this.headerHeight;
            // 记录上次滑动距离为 loading状态高度
            this.lastEndTranslateDistance = this.headerHeight;
            this.status = 'loading';
            this.runAnimation();
            this.$emit('refresh');
        } else {
            this.done();
        }

    }




    /**
     *  是否在最顶部
     */
    private isTopmost() {
        const body = document.body || document.documentElement;
        const scrollTop = body.scrollTop || window.pageYOffset || 0;
        return scrollTop === 0;
    }


    /**
     * 获取手指是否往下滑动
     * @param moveX  
     * @param moveY 
     */
    private isPullDown(moveX: number, moveY: number) {
        const angle = this.getAngle(moveX, moveY);
        return angle >= 45 && angle < 135;
    }

    /**
     * 获取手指滑动角度
     * @param moveX  
     * @param moveY 
     */
    private getAngle(moveX: number, moveY: number) {
        return Math.atan2(moveY - this.startY, moveX - this.startX) * 180 / Math.PI;
    }

    /**
     * 获取滑动距离
     * @param moveY 
     */
    private getDistance(moveY: number) {
        let d = (moveY - this.startY) * 0.6 + this.lastEndTranslateDistance;
        if (d < 0) {
            d = 0;
        }
        return d;
    }

    /**
     * 执行动画
     */
    private runAnimation() {
        if (this.animationIndex >= this.icons.length - 1) {
            this.animationIndex = 0;
        } else {
            this.animationIndex++;
        }
        if (this.status === 'loading') {
            setTimeout(() => {
                this.runAnimation();
            }, this.animationStep);
        } else {
            this.animationIndex = this.defaultIndex;
        }
    }
}
